<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">


  <link rel="icon" type="image/png" sizes="16x16" href="https://cdn.jsdelivr.net/gh/CNhuazhu/Image/avatar.jpg">

<link rel="stylesheet" href="/next/css/main.css">



<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.3/css/all.min.css" integrity="sha256-2H3fkXt6FEmrReK448mDVGKb3WW2ZZw35gI7vqHOE4Y=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" integrity="sha256-Vzbj7sDDS/woiFS3uNKo8eIuni59rjyNGtXfstRzStA=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"cnhuazhu.gitee.io","root":"/next/","images":"/next/images","scheme":"Mist","version":"8.6.1","exturl":false,"sidebar":{"position":"left","Muse | Mist":320,"display":"post","padding":18,"offset":12},"copycode":true,"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":true,"mediumzoom":true,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/next/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/next/js/config.js"></script>
<meta name="description" content="记录操作系统学习历程">
<meta property="og:type" content="article">
<meta property="og:title" content="操作系统学习笔记-信号量相关问题">
<meta property="og:url" content="https://cnhuazhu.gitee.io/next/2021/04/25/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E4%BF%A1%E5%8F%B7%E9%87%8F%E7%9B%B8%E5%85%B3%E9%97%AE%E9%A2%98/index.html">
<meta property="og:site_name" content="花猪のBlog">
<meta property="og:description" content="记录操作系统学习历程">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://cdn.jsdelivr.net/gh/CNhuazhu/Image/OS%E5%93%B2%E5%AD%A6%E5%AE%B6%E8%BF%9B%E9%A4%90%E9%97%AE%E9%A2%98.png">
<meta property="article:published_time" content="2021-04-25T09:30:29.000Z">
<meta property="article:modified_time" content="2021-06-30T12:31:09.556Z">
<meta property="article:author" content="花猪">
<meta property="article:tag" content="操作系统">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://cdn.jsdelivr.net/gh/CNhuazhu/Image/OS%E5%93%B2%E5%AD%A6%E5%AE%B6%E8%BF%9B%E9%A4%90%E9%97%AE%E9%A2%98.png">


<link rel="canonical" href="https://cnhuazhu.gitee.io/next/2021/04/25/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E4%BF%A1%E5%8F%B7%E9%87%8F%E7%9B%B8%E5%85%B3%E9%97%AE%E9%A2%98/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://cnhuazhu.gitee.io/next/2021/04/25/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E4%BF%A1%E5%8F%B7%E9%87%8F%E7%9B%B8%E5%85%B3%E9%97%AE%E9%A2%98/","path":"2021/04/25/操作系统/操作系统学习笔记-信号量相关问题/","title":"操作系统学习笔记-信号量相关问题"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>操作系统学习笔记-信号量相关问题 | 花猪のBlog</title>
  




  <noscript>
    <link rel="stylesheet" href="/next/css/noscript.css">
  </noscript>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/next/" class="brand" rel="start">
      <i class="logo-line"></i>
      <h1 class="site-title">花猪のBlog</h1>
      <i class="logo-line"></i>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu">
        <li class="menu-item menu-item-主站"><a href="https://cnhuazhu.top/" rel="noopener" target="_blank"><i class="fas fa-chevron-right fa-fw"></i>主站</a></li>
        <li class="menu-item menu-item-home"><a href="/next/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li>
        <li class="menu-item menu-item-tags"><a href="/next/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签<span class="badge">14</span></a></li>
        <li class="menu-item menu-item-categories"><a href="/next/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类<span class="badge">8</span></a></li>
        <li class="menu-item menu-item-archives"><a href="/next/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档<span class="badge">53</span></a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</div>
        
  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>

  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%89%8D%E8%A8%80"><span class="nav-number">1.</span> <span class="nav-text">前言</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E6%AD%A3%E6%96%87"><span class="nav-number">2.</span> <span class="nav-text">正文</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%94%9F%E4%BA%A7%E8%80%85-%E6%B6%88%E8%B4%B9%E8%80%85%E9%97%AE%E9%A2%98"><span class="nav-number">2.1.</span> <span class="nav-text">生产者-消费者问题</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%A4%9A%E7%94%9F%E4%BA%A7%E8%80%85-%E5%A4%9A%E6%B6%88%E8%B4%B9%E8%80%85%E9%97%AE%E9%A2%98"><span class="nav-number">2.2.</span> <span class="nav-text">多生产者-多消费者问题</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%90%B8%E7%83%9F%E8%80%85%E9%97%AE%E9%A2%98"><span class="nav-number">2.3.</span> <span class="nav-text">吸烟者问题</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%AF%BB%E8%80%85-%E5%86%99%E8%80%85%E9%97%AE%E9%A2%98"><span class="nav-number">2.4.</span> <span class="nav-text">读者-写者问题</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%93%B2%E5%AD%A6%E5%AE%B6%E8%BF%9B%E9%A4%90%E9%97%AE%E9%A2%98"><span class="nav-number">2.5.</span> <span class="nav-text">哲学家进餐问题</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%90%8E%E8%AE%B0"><span class="nav-number">3.</span> <span class="nav-text">后记</span></a></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-overview">
            <div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="花猪"
      src="https://cdn.jsdelivr.net/gh/CNhuazhu/Image/avatar.jpg">
  <p class="site-author-name" itemprop="name">花猪</p>
  <div class="site-description" itemprop="description">为了获得不同的阅读体验，建立此分站。<br>（可在导航栏搜索想要查看的文章）<br><br>本站主题：NEXT 8.6.1</div>
</div>
<div class="site-state-wrap site-overview-item animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/next/archives/">
        
          <span class="site-state-item-count">53</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/next/categories/">
          
        <span class="site-state-item-count">8</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/next/tags/">
          
        <span class="site-state-item-count">14</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author site-overview-item animated">
      <span class="links-of-author-item">
        <a href="https://github.com/CNhuazhu" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;CNhuazhu" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
  </div>



          </div>
        </div>
      </div>
    </div>
  </aside>
  <div class="sidebar-dimmer"></div>


    </header>

    
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>

  <a href="https://github.com/CNhuazhu" class="github-corner" title="Follow me on GitHub" aria-label="Follow me on GitHub" rel="noopener" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cnhuazhu.gitee.io/next/2021/04/25/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E4%BF%A1%E5%8F%B7%E9%87%8F%E7%9B%B8%E5%85%B3%E9%97%AE%E9%A2%98/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="https://cdn.jsdelivr.net/gh/CNhuazhu/Image/avatar.jpg">
      <meta itemprop="name" content="花猪">
      <meta itemprop="description" content="为了获得不同的阅读体验，建立此分站。<br>（可在导航栏搜索想要查看的文章）<br><br>本站主题：NEXT 8.6.1">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="花猪のBlog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          操作系统学习笔记-信号量相关问题
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2021-04-25 17:30:29" itemprop="dateCreated datePublished" datetime="2021-04-25T17:30:29+08:00">2021-04-25</time>
    </span>
      <span class="post-meta-item">
        <span class="post-meta-item-icon">
          <i class="far fa-calendar-check"></i>
        </span>
        <span class="post-meta-item-text">更新于</span>
        <time title="修改时间：2021-06-30 20:31:09" itemprop="dateModified" datetime="2021-06-30T20:31:09+08:00">2021-06-30</time>
      </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/next/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/" itemprop="url" rel="index"><span itemprop="name">学习笔记</span></a>
        </span>
    </span>

  
    <span id="/next/2021/04/25/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E4%BF%A1%E5%8F%B7%E9%87%8F%E7%9B%B8%E5%85%B3%E9%97%AE%E9%A2%98/" class="post-meta-item leancloud_visitors" data-flag-title="操作系统学习笔记-信号量相关问题" title="阅读次数">
      <span class="post-meta-item-icon">
        <i class="far fa-eye"></i>
      </span>
      <span class="post-meta-item-text">阅读次数：</span>
      <span class="leancloud-visitors-count"></span>
    </span>
    <span id="/next/2021/04/25/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E4%BF%A1%E5%8F%B7%E9%87%8F%E7%9B%B8%E5%85%B3%E9%97%AE%E9%A2%98/" class="post-meta-item twikoo_visitors" data-flag-title="操作系统学习笔记-信号量相关问题" title="阅读次数">
      <span class="post-meta-item-icon">
        <i class="far fa-eye"></i>
      </span>
      <span class="post-meta-item-text">阅读次数：</span>
      <span id="twikoo_visitors"></span>
    </span>
  
      </div>
      <div class="post-meta">
    <span class="post-meta-item" title="本文字数">
      <span class="post-meta-item-icon">
        <i class="far fa-file-word"></i>
      </span>
      <span class="post-meta-item-text">本文字数：</span>
      <span>11k</span>
    </span>
    <span class="post-meta-item" title="阅读时长">
      <span class="post-meta-item-icon">
        <i class="far fa-clock"></i>
      </span>
      <span class="post-meta-item-text">阅读时长 &asymp;</span>
      <span>10 分钟</span>
    </span>
</div>

            <div class="post-description">记录操作系统学习历程</div>
        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p><em>正在学习操作系统，记录笔记。</em></p>
<p>（补充一下与信号量相关的问题类型以及解决思路）</p>
<blockquote>
<p>参考资料：</p>
<p>《操作系统（精髓与设计原理 第6版） 》</p>
<p>王道考研：<a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1YE411D7nH?from=search&seid=12220712596266554764">2019 王道考研 操作系统_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili</a></p>
</blockquote>
<hr>
<h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><p>先声明：为了方便（就是我懒），下文可能会用<code>P操作</code>来指代<code>semWait(x)</code>；用<code>V操作</code>来指代<code>semSignal(x)</code>。</p>
<h2 id="生产者-消费者问题"><a href="#生产者-消费者问题" class="headerlink" title="生产者-消费者问题"></a>生产者-消费者问题</h2><p>问题描述：</p>
<ul>
<li><p>系统中有一组生产者进程和一组消费者进程，生产者进程每次生产一个产品放入缓冲区，消费者进程每次从缓冲区中取出一个产品并使用。（注：这里的“产品理解为某种数据”）</p>
</li>
<li><p>生产者、消费者共享一个初始为空、大小为n的缓冲区。</p>
</li>
<li><p>只有缓冲区没满时，生产者才能把产品放入缓冲区，否则必须等待。</p>
</li>
<li><p>只有缓冲区不空时，消费者才能从中取出产品，否则必须等待。</p>
</li>
<li><p>缓冲区是临界资源，各进程必须互斥地访问（只允许一个生产者放入消息，也只允许一个消费者拿出消息）。</p>
<blockquote>
<p>再次详细解释一下最后一点。意思是，同一个时刻只能是一个生产者或者一个消费者操作缓冲区，禁止以下情况：多个生产者或者多个消费者操作缓冲区；同样，一个生产者和一个消费者同时操作也是禁止的。</p>
</blockquote>
</li>
</ul>
<p>分析：</p>
<ul>
<li>互斥关系：不允许有两方及以上同时访问缓冲区。</li>
<li>同步关系：存在两种同步关系，分别为缓冲区满、缓冲区空。（当消费者消费一个产品，应该告诉生产者，缓冲区有一个空位；当生产者生产一个商品，应该告诉消费者，缓冲区非空）</li>
</ul>
<p>所以根据以上分析得知：应该需要三对P、V操作。因此需要定义如下三个信号量：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">semaphore mutex = <span class="number">1</span>;    <span class="comment">//互斥信号量，实现对缓冲区的访问</span></span><br><span class="line">semaphore empty = n;    <span class="comment">//同步信号量，表示空闲缓冲区的数量（初始值为n）</span></span><br><span class="line">semaphore full = <span class="number">0</span>;    <span class="comment">//同步信号量，表示产品的数量，也即非缓冲区的数量（初始值为0）</span></span><br></pre></td></tr></table></figure>

<p>实现：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*producer*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">producer</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="comment">/*生产一个产品*/</span>;</span><br><span class="line">        <span class="built_in">semWait</span>(empty);    <span class="comment">//检查有无缓冲区可用  (Ⅰ)</span></span><br><span class="line">        <span class="built_in">semWait</span>(mutex);    <span class="comment">//互斥操作  (Ⅱ)</span></span><br><span class="line">        <span class="comment">/*将产品放入缓冲区*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(mutex);    <span class="comment">//互斥操作</span></span><br><span class="line">        <span class="built_in">semSignal</span>(full);    <span class="comment">//告诉消费者“生产了一个产品”</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*consumer*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">consumer</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="built_in">semWait</span>(full);    <span class="comment">//检查有无产品（非空缓冲区）  (Ⅲ)</span></span><br><span class="line">        <span class="built_in">semWait</span>(mutex);    <span class="comment">//互斥操作  (Ⅳ)</span></span><br><span class="line">        <span class="comment">/*从缓冲区中取出一个产品*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(mutex);    <span class="comment">//互斥操作</span></span><br><span class="line">        <span class="built_in">semSignal</span>(empty);    <span class="comment">//告诉生产者“取走了一个产品，缓冲区有空闲”</span></span><br><span class="line">        <span class="comment">/*使用产品*/</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">parbegin</span>(<span class="built_in">producer</span>(), <span class="built_in">consumer</span>());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>思考：能否改变相邻P、V操作的顺序？（即调换<code>(Ⅰ)</code>、<code>(Ⅱ)</code>以及<code>(Ⅲ)</code>、<code>(Ⅳ)</code>的顺序）</p>
<p>分析：</p>
<ul>
<li>分析此种情况：若缓冲区内已经放满产品，则empty=0，full=n。</li>
<li>则生产者先执行<code>(Ⅱ)</code>（semWait(mutex)）操作使得mutex变为0，在执行<code>(Ⅰ)</code>操作（semWait(empty)），由于已经没有空闲缓冲区，因此生产者被阻塞。接着切换至消费者进程。消费者进程首先执行<code>(Ⅳ)</code>（semWait(mutex)）操作，由于mutex为0，即生产者还没有释放对临界资源的控制权，因此消费者也被阻塞。</li>
<li>这就出现了<strong>死锁</strong>的情况（生产者等待消费者释放空闲缓冲区，而消费者又等待生产者释放临界区）</li>
<li>同样的我们分析另一种情况：若缓冲区中没有产品，即empty=n，full=0。按照<code>(Ⅳ)``(Ⅲ)``(Ⅱ)</code>的顺序也会发生死锁情况。</li>
</ul>
<p>因此：</p>
<ul>
<li><strong>实现互斥的P操作一定要在实现同步的P操作之后。</strong></li>
<li><strong>V操作不会导致进程阻塞，因此两个V操作顺序可以交换。</strong></li>
</ul>
<p>还需要注意的一点：</p>
<p>生产者<code>“生产一个产品”</code>的操作以及消费者<code>“使用产品”</code>的操作可以放置P、V操作之间，但是要意识到这些操作是非必要的，如果放置在临界区操作则会导致其代码量变大，在一个进程访问临界区的同时就要耗费更多的时间，这会导致进程之间的并发度降低。（<strong>只在临界区做必要操作</strong>）</p>
</blockquote>
<h2 id="多生产者-多消费者问题"><a href="#多生产者-多消费者问题" class="headerlink" title="多生产者-多消费者问题"></a>多生产者-多消费者问题</h2><p>问题描述：</p>
<p>桌子上有一只盘子，每次只能向其中放入一个水果。爸爸专向盘子中放苹果，妈妈专向盘子中放橘子，儿子专等着吃盘子中的橘子，女儿专等着吃盘子中的苹果。只有盘子空时，爸爸或妈妈才可向盘子中放一个水果。仅当盘子中有自己需要的水果时，儿子或女儿可以从盘子中取出水果。用P、V操作实现上述过程。</p>
<p>分析：</p>
<ul>
<li>互斥关系：将盘子视为缓冲区。每个人（进程）对其访问都是互斥的。</li>
<li>同步关系：<ol>
<li>父亲将苹果放入盘子后，女儿才能取苹果。</li>
<li>母亲将橘子放入盘子后，儿子才能取橘子。</li>
<li>只有盘子为空时，父亲或母亲才能放入水果。（盘子为空事件可由儿子或者女儿触发）</li>
</ol>
</li>
</ul>
<p>所以根据以上分析得知，需要定义如下四个信号量：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">semaphore mutex = <span class="number">1</span>;    <span class="comment">//实现互斥访问盘子（临界区）</span></span><br><span class="line">semaphore apple = <span class="number">0</span>;    <span class="comment">//盘子中有几个苹果（初始值为0）</span></span><br><span class="line">semaphore orange = <span class="number">0</span>;    <span class="comment">//盘子中有几个橘子（初始值为0）</span></span><br><span class="line">semaphore plate = <span class="number">1</span>;    <span class="comment">//盘子中还可以放多少个水果</span></span><br></pre></td></tr></table></figure>

<p>实现：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*dad*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">dad</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="comment">/*准备一个苹果*/</span>;</span><br><span class="line">        <span class="built_in">semWait</span>(plate);    <span class="comment">//检查盘子是否为空</span></span><br><span class="line">        <span class="built_in">semWait</span>(mutex);    <span class="comment">//实现对盘子这一缓冲区的互斥访问</span></span><br><span class="line">        <span class="comment">/*把苹果放入盘子*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(mutex);</span><br><span class="line">        <span class="built_in">semSignal</span>(apple);    <span class="comment">//告诉女儿“盘子里有苹果了”</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*mom*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">mom</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="comment">/*准备一个橘子*/</span>;</span><br><span class="line">        <span class="built_in">semWait</span>(plate);    <span class="comment">//检查盘子是否为空</span></span><br><span class="line">        <span class="built_in">semWait</span>(mutex);    <span class="comment">//实现对盘子这一缓冲区的互斥访问</span></span><br><span class="line">        <span class="comment">/*把橘子放入盘子*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(mutex);</span><br><span class="line">        <span class="built_in">semSignal</span>(orange);    <span class="comment">//告诉儿子“盘子里有橘子了”</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*daughter*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">daughter</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="built_in">semWait</span>(apple);    <span class="comment">//检查盘子里有没有苹果</span></span><br><span class="line">        <span class="built_in">semWait</span>(mutex);    <span class="comment">//实现对盘子这一缓冲区的互斥访问</span></span><br><span class="line">        <span class="comment">/*从盘子中取出苹果*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(mutex);</span><br><span class="line">        <span class="built_in">semSignal</span>(plate);    <span class="comment">//告诉父母“盘子为空了”</span></span><br><span class="line">        <span class="comment">/*吃掉苹果*/</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*son*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">son</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="built_in">semWait</span>(orange);    <span class="comment">//检查盘子里有没有橘子</span></span><br><span class="line">        <span class="built_in">semWait</span>(mutex);    <span class="comment">//实现对盘子这一缓冲区的互斥访问</span></span><br><span class="line">        <span class="comment">/*从盘子中取出橘子*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(mutex);</span><br><span class="line">        <span class="built_in">semSignal</span>(plate);    <span class="comment">//告诉父母“盘子为空了”</span></span><br><span class="line">        <span class="comment">/*吃掉橘子*/</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">parbegin</span>(<span class="built_in">dad</span>(), <span class="built_in">mom</span>(), <span class="built_in">daughter</span>(), <span class="built_in">son</span>());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>思考：上述案例可不可以不使用互斥信号量（mutex）呢？</p>
<p>分析（删除上述代码中所有的<code>semWait(mutex)</code>以及<code>semSignal(mutex)</code>操作）：</p>
<ul>
<li>刚开始，儿子、女儿进程即使上处理机运行也会被阻塞。</li>
<li>如果刚开始是父亲进程先上处理机运行，则：<ul>
<li>父亲执行<code>semWait(plate)</code>操作，可以访问盘子。</li>
<li>母亲执行<code>semWait(plate)</code>操作，被阻塞等待盘子。</li>
<li>父亲执行<code>semSignal(apple)</code>操作，放入苹果。</li>
<li>女儿i进程被唤醒（其他进程即使运行也会阻塞）。</li>
<li>女儿执行<code>semWait(apple)</code>操作，访问盘子。并接着执行<code>semSignal(plate)</code>操作。</li>
<li>父亲或者母亲进程再次被唤醒（儿子进程访问会被阻塞）。</li>
<li>….</li>
</ul>
</li>
</ul>
<p>以上分析可以得出结论，即便没有互斥信号量（mutex），也不影响正常运行。</p>
<p>原因在于：本题中的缓冲区大小为1，在任何时刻，apple、orange、plate三个同步信号量中最多只有一个是1。因此在任何时刻，最多只有一个进程的<code>P操作</code>不会被阻塞，并顺利地进入临界区。</p>
<p>但是加入此题盘子的容量为2及以上，就无法保证进程互斥访问盘子。（分析过程省略）</p>
<p><strong>最好直接就设置互斥信号量（mutex），以防出错。</strong></p>
</blockquote>
<h2 id="吸烟者问题"><a href="#吸烟者问题" class="headerlink" title="吸烟者问题"></a>吸烟者问题</h2><p>问题描述：</p>
<p>假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它，但是要卷起并抽掉一支烟，抽烟者需要有三种材料：烟草、纸和胶水。三个抽烟者中，第一个拥有烟草、第二个拥有纸、第三个拥有胶水。供应者进程无限地提供三种材料，供应者每次将两种材料放桌子上，拥有剩下第三种材料的抽烟者卷一根烟并抽掉它，并给供应者进程一个信号告诉完成了，供应者就会放另外两种材料再桌上，这个过程一直重复（让三个抽烟者轮流地抽烟）</p>
<p>分析：</p>
<ul>
<li><p>互斥关系：将桌子视为缓冲区，每个进程对其访问都是互斥的。</p>
<blockquote>
<p>值得注意的是，尽管供应者每次会将两种材料放置在桌子上，但是桌子（缓冲区）的容量仍为1，我们应该将不同的两种材料视为一种组合：</p>
<ul>
<li>组合一：纸 + 胶水</li>
<li>组合二：烟草 + 胶水</li>
<li>组合三：烟草 + 纸</li>
</ul>
</blockquote>
</li>
<li><p>同步关系：</p>
<ol>
<li>桌上有组合一 → 第一个抽烟者取走东西。</li>
<li>桌上有组合二 → 第二个抽烟者取走东西。</li>
<li>桌上有组合三 → 第三个抽烟者取走东西。</li>
<li>抽烟者抽完烟 → 供应者将下一种组合材料放到桌子上。</li>
</ol>
</li>
<li><p>需要让三个抽烟者轮流地抽烟。</p>
</li>
</ul>
<p>所以根据以上分析得知，需要定义如下四个信号量：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">semaphore offer1 = <span class="number">0</span>;    <span class="comment">//桌上组合一的数量</span></span><br><span class="line">semaphore offer2 = <span class="number">0</span>;    <span class="comment">//桌上组合二的数量</span></span><br><span class="line">semaphore offer3 = <span class="number">0</span>;    <span class="comment">//桌上组合三的数量</span></span><br><span class="line">semaphore finish = <span class="number">0</span>;    <span class="comment">//抽烟是否完成</span></span><br><span class="line"><span class="keyword">int</span> i = <span class="number">0</span>;    <span class="comment">//用于实现“三个抽烟者轮流地抽烟”</span></span><br></pre></td></tr></table></figure>

<p>实现：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*provider*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">provider</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="keyword">if</span>(i == <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="comment">/*将组合一放桌上*/</span>;</span><br><span class="line">            <span class="built_in">semSignal</span>(offer1);    <span class="comment">//告诉第一个抽烟者“桌上有组合一”</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span>(i == <span class="number">1</span>)&#123;</span><br><span class="line">            <span class="comment">/*将组合二放桌上*/</span>;</span><br><span class="line">            <span class="built_in">semSignal</span>(offer2);    <span class="comment">//告诉第二个抽烟者“桌上有组合二”</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span>(i == <span class="number">2</span>)&#123;</span><br><span class="line">            <span class="comment">/*将组合三放桌上*/</span>;</span><br><span class="line">            <span class="built_in">semSignal</span>(offer3);    <span class="comment">//告诉第三个抽烟者“桌上有组合三”</span></span><br><span class="line">        &#125;</span><br><span class="line">        i = (i + <span class="number">1</span>) % <span class="number">3</span>;</span><br><span class="line">        <span class="built_in">semWait</span>(finish);    <span class="comment">//判断抽烟者是否已经完成吸烟</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*smoker1*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">smoker1</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="built_in">semWait</span>(offer1);    <span class="comment">//判断桌子上有没有组合一</span></span><br><span class="line">        <span class="comment">/*从桌子上拿走组合一；卷烟；抽掉*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(finish);    <span class="comment">//告诉提供者“桌子上已经空了”</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*smoker2*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">smoker2</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="built_in">semWait</span>(offer2);    <span class="comment">//判断桌子上有没有组合二</span></span><br><span class="line">        <span class="comment">/*从桌子上拿走组合二；卷烟；抽掉*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(finish);    <span class="comment">//告诉提供者“桌子上已经空了”</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*smoker3*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">smoker3</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="built_in">semWait</span>(offer3);    <span class="comment">//判断桌子上有没有组合三</span></span><br><span class="line">        <span class="comment">/*从桌子上拿走组合三；卷烟；抽掉*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(finish);    <span class="comment">//告诉提供者“桌子上已经空了”</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">parbegin</span>(<span class="built_in">provider</span>(), <span class="built_in">smoker1</span>(), <span class="built_in">smoker2</span>(), <span class="built_in">smoker3</span>());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>分析：是否需要专门再设置一个互斥信号量（mutex）？</p>
<p>因为桌子的容量为1（同上面一个例子相同），因此不必设置也不会出错。</p>
</blockquote>
<h2 id="读者-写者问题"><a href="#读者-写者问题" class="headerlink" title="读者-写者问题"></a>读者-写者问题</h2><p>问题描述：</p>
<p>有读者和写者两组并发进程，共享一个文件，当两个或两个以上的读进程同时访问共享数据时不会产生副作用，但若某个写进程和其他进程（读进程或写进程）同时访问共享数据时则可能导致数据不一致的错误。因此我们要求：</p>
<ul>
<li>允许多个读者可以同时对文件执行读操作；</li>
<li>只允许一个写者往文件中写信息；</li>
<li>任一写者在完成写操作之前不允许其他读者或写者工作；</li>
<li>写者执行写操作前，应让已有的读者和写者全部退出。</li>
</ul>
<p>分析：</p>
<ul>
<li><p>互斥关系：</p>
<ol>
<li><p>写进程——写进程</p>
</li>
<li><p>写进程——读进程</p>
<p>（读进程之间不存在互斥关系，因此可以同时读文件，如何实现该操作是此类问题的关键）</p>
</li>
</ol>
</li>
</ul>
<p>所以根据以上分析得知，需要定义如下三个信号量：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">semaphore rw = <span class="number">1</span>;    <span class="comment">//用于实现对文件的互斥访问。表示当前是否有进程在访问共享文件</span></span><br><span class="line"><span class="keyword">int</span> count = <span class="number">0</span>;    <span class="comment">//用于记录当前有几个读进程在访问文件</span></span><br><span class="line">semaphore mutex = <span class="number">1</span>;    <span class="comment">//用于保证对count变量的互斥访问</span></span><br></pre></td></tr></table></figure>

<p>实现：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*writer*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">writer</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="built_in">semWait</span>(rw);    <span class="comment">//在写文件之前“上锁”</span></span><br><span class="line">        <span class="comment">/*写文件*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(rw);    <span class="comment">//在写完之后“解锁”</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*reader*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">reader</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="built_in">semWait</span>(mutex);    <span class="comment">//各读进程互斥访问count</span></span><br><span class="line">        <span class="keyword">if</span>(count == <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="built_in">semWait</span>(rw);    <span class="comment">//第一个读进程负责“上锁”</span></span><br><span class="line">        &#125;</span><br><span class="line">        count++;    <span class="comment">//访问文件的读进程数加一</span></span><br><span class="line">        <span class="built_in">semSignal</span>(mutex);    </span><br><span class="line">        <span class="comment">/*读文件*/</span>;</span><br><span class="line">        <span class="built_in">semWait</span>(mutex);    <span class="comment">//各读进程互斥访问count</span></span><br><span class="line">        count--;    <span class="comment">//访问文件的读进程数减一</span></span><br><span class="line">        <span class="keyword">if</span>(count == <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="built_in">semSignal</span>(rw);    <span class="comment">//最后一个读进程负责“解锁”</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">semSignal</span>(mutex);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">parbegin</span>(<span class="built_in">writer</span>(), <span class="built_in">reader1</span>(), <span class="built_in">reader2</span>(),...,<span class="built_in">readern</span>());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>分析：</p>
<p>mutex变量的设置是为了解决读进程对count的访问（解决多个读进程访问的操作）</p>
<ul>
<li>第一个读进程执行<code>semWait(mutex)</code>操作，顺利通过，并执行之后的<code>semWait(rw)</code>操作（保证了读进程与写进程的互斥）</li>
<li>若此时另一个读进程访问，在执行<code>semWait(mutex)</code>操作会被阻塞，直到第一个读进程执行<code>semSignal(mutex)</code>操作（“解锁”对count的访问，注意此时count值为1）</li>
<li>当count“解锁”后，另一个读进程再执行<code>semWait(mutex)</code>操作，判断count的值不为0，直接跳过<code>semWait(rw)</code>访问，这样就避免了各个读进程之间的互斥访问</li>
</ul>
<p>再仔细体会会发现上述代码存在一个潜在的问题，即：如果读进程一直在不停地访问（count值永不为0），就无法对文件“解锁”，写者进程就可能“饿死”。</p>
<p>因此该种写法是<strong>读进程优先</strong>。</p>
</blockquote>
<p>如何实现写进程优先呢？</p>
<p>这里我们再增加一个信号量：<code>semaphore w = 1</code>。</p>
<p>即现在一共有如下四个信号量：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">semaphore rw = <span class="number">1</span>;    <span class="comment">//用于实现对文件的互斥访问。表示当前是否有进程在访问共享文件</span></span><br><span class="line"><span class="keyword">int</span> count = <span class="number">0</span>;    <span class="comment">//用于记录当前有几个读进程在访问文件</span></span><br><span class="line">semaphore mutex = <span class="number">1</span>;    <span class="comment">//用于保证对count变量的互斥访问</span></span><br><span class="line">semaphore w = <span class="number">1</span>;    <span class="comment">//用于实现“写进程优先”</span></span><br></pre></td></tr></table></figure>

<p>实现：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*writer*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">writer</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="built_in">semWait</span>(w);    <span class="comment">//Ⅰ</span></span><br><span class="line">        <span class="built_in">semWait</span>(rw);    <span class="comment">//在写文件之前“上锁”  Ⅱ</span></span><br><span class="line">        <span class="comment">/*写文件*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(rw);    <span class="comment">//在写完之后“解锁”  Ⅲ</span></span><br><span class="line">        <span class="built_in">semSignal</span>(w);    <span class="comment">//Ⅳ</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*reader*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">reader</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="built_in">semWait</span>(w);    <span class="comment">//Ⅴ</span></span><br><span class="line">        <span class="built_in">semWait</span>(mutex);    <span class="comment">//各读进程互斥访问count  </span></span><br><span class="line">        <span class="keyword">if</span>(count == <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="built_in">semWait</span>(rw);    <span class="comment">//第一个读进程负责“上锁”  Ⅵ</span></span><br><span class="line">        &#125;</span><br><span class="line">        count++;    <span class="comment">//访问文件的读进程数加一</span></span><br><span class="line">        <span class="built_in">semSignal</span>(mutex);</span><br><span class="line">        <span class="built_in">semSignal</span>(w);    <span class="comment">//Ⅶ</span></span><br><span class="line">        <span class="comment">/*读文件*/</span>;</span><br><span class="line">        <span class="built_in">semWait</span>(mutex);    <span class="comment">//各读进程互斥访问count</span></span><br><span class="line">        count--;    <span class="comment">//访问文件的读进程数减一</span></span><br><span class="line">        <span class="keyword">if</span>(count == <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="built_in">semSignal</span>(rw);    <span class="comment">//最后一个读进程负责“解锁”  Ⅷ</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">semSignal</span>(mutex);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">parbegin</span>(<span class="built_in">writer</span>(), <span class="built_in">reader1</span>(), <span class="built_in">reader2</span>(),...,<span class="built_in">readern</span>());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>分析：<em>（容我吐槽一下，简直头皮发麻）</em></p>
<ol>
<li><p>读者1 → 读者2</p>
<ul>
<li>第一个读进程顺利通过<code>Ⅴ（semWait(w)）</code>操作，并对文件（rw）“上锁”，count++，…，到最后顺利地读文件。</li>
<li>第二个读进程同上。</li>
<li>即在增添了<code>Ⅴ（semWait(w)）</code>操作以及<code>Ⅶ（semSignal(w)）</code>对多个读进程并发访问文件是没有影响的。</li>
</ul>
</li>
<li><p>写者1 → 写者2</p>
<ul>
<li>第一个写进程会顺利通过<code>Ⅰ（semWait(w)）</code>操作，<code>Ⅱ（semWait(rw)）</code>操作，并顺利写文件。</li>
<li>第二个写进程如果并发执行会被阻塞在Ⅰ处，直到第一个写进程执行<code>Ⅳ（semSignal(w)）</code>“解锁写操作”，才可以继续执行。</li>
<li>实现了多个写进程之间的互斥。</li>
</ul>
</li>
<li><p>写者1 → 读者1</p>
<ul>
<li>写着进程顺利通过<code>Ⅰ（semWait(w)）</code>操作，<code>Ⅱ（semWait(rw)）</code>操作，开始写文件。</li>
<li>此时如果读进程要执行，就会被阻塞在<code>Ⅴ（semWait(w)）</code>操作，直到写进程执行完<code>Ⅳ（semSignal(w)）</code>“解锁写操作”，才可以继续执行。</li>
<li>实现了读者与写者的互斥。</li>
</ul>
</li>
<li><p>读者1 → 写者1 → 读者2</p>
<ul>
<li>第一个读进程可以顺利执行到<code>读文件</code>操作。</li>
<li>此时若写进程执行，可以顺利执行<code>Ⅰ（semWait(w)）</code>操作，但在<code>Ⅱ（semWait(rw)）</code>操作会被阻塞。</li>
<li>然后第二个读进程并发执行，由于上一步读进程顺利执行<code>Ⅰ（semWait(w)）</code>操作，所以第二个读进程会被阻塞在<code>Ⅴ（semWait(w)）</code>操作。</li>
<li>直到第一个读进程执行完<code>Ⅷ（semSignal(rw)）</code>操作对文件“解锁”，此时写进程就可以被唤醒，开始写文件。</li>
<li>第二个读进程依然被阻塞在<code>Ⅴ（semWait(w)）</code>操作，直到写进程执行完<code>Ⅳ（semSignal(w)）</code>操作，第二个读进程才可以继续执行。</li>
<li>所以这种情况并不会导致写进程“饥饿”。</li>
</ul>
</li>
<li><p>写者1 → 读者1 → 写者2</p>
<ul>
<li><p>第一个写进程顺利执行前面的操作，开始写文件。</p>
</li>
<li><p>此时如果读进程执行，则会被阻塞在<code>Ⅴ（semWait(w)）</code>操作。</p>
</li>
<li><p>此时如果第二个写进程执行，则也会被阻塞在<code>Ⅰ（semWait(w)）</code>操作。</p>
</li>
<li><p>如果第一个写进程执行完<code>Ⅳ（semSignal(w)）</code>操作，则此时会根据“先来先得”的原则，首先唤醒读进程，读进程顺利执行。</p>
</li>
<li><p>然后读进程会执行<code>Ⅵ（semWait(rw)）</code>操作对文件“上锁”，在执行完<code>Ⅶ（semWait(w)）</code>操作时释放对写进程的操作，第二个写进程就继续执行，但是会被阻塞在<code>Ⅱ（semWait(rw)）</code>操作。</p>
</li>
<li><p>读进程继续执行，直到结束，释放对文件的访问控制，第二个写进程才可以顺利执行。</p>
</li>
<li><blockquote>
<p>在这种情况我们可以分析出，尽管不会使得写进程“饥饿”，但也不是真正的“写进程优先”，而是符合相对公平的先来先服务的原则。</p>
</blockquote>
</li>
</ul>
</li>
</ol>
</blockquote>
<h2 id="哲学家进餐问题"><a href="#哲学家进餐问题" class="headerlink" title="哲学家进餐问题"></a>哲学家进餐问题</h2><p>问题描述：</p>
<p>一张圆桌上坐着5名哲学家，每两个哲学家之间的桌上摆一根筷子，桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐，哲学家在思考时，并不影响他人。只有当哲学家饥饿时，才试图拿起左、右两根筷子（一根一根地拿起）。如果筷子已在他人手上，则需等待。饥饿的哲学家只有同时拿起两根筷子才可以开始进餐，当进餐完毕后，放下筷子继续思考。</p>
<p><img src="https://cdn.jsdelivr.net/gh/CNhuazhu/Image/OS%E5%93%B2%E5%AD%A6%E5%AE%B6%E8%BF%9B%E9%A4%90%E9%97%AE%E9%A2%98.png"></p>
<p>分析：</p>
<ul>
<li><p>互斥关系：系统中有5个哲学家进程，5位哲学家与左右邻居对其中间筷子的访问是互斥关系。</p>
<blockquote>
<p>这个问题中只有互斥关系，但与之前遇到的问题不同的是，每个哲学家进程需要同时持有两个临界资源才能开始吃饭。如何避免临界资源分配不当造成的死锁现象，是哲学家问题的关键。</p>
</blockquote>
</li>
</ul>
<p>所以根据以上分析得知，需要定义如下信号量数组以及一个互斥信号量：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">semaphore chopstick[<span class="number">5</span>] = &#123;<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>&#125;;    <span class="comment">//用于实现对5根筷子的互斥访问</span></span><br><span class="line">semaphore mutex = <span class="number">1</span>;    <span class="comment">//互斥地取筷子</span></span><br></pre></td></tr></table></figure>

<p>并规定对哲学家按0~4编号，哲学家 i 左边的筷子编号为 i，右边的筷子编号为 <code>( i + 1 ) % 5</code>。</p>
<p>实现：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*philosopher*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">philosopher</span><span class="params">(<span class="keyword">int</span> i)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="comment">/*思考*/</span>;</span><br><span class="line">        <span class="built_in">semWait</span>(mutex);</span><br><span class="line">        <span class="built_in">semWait</span>(chopstick[i]);    <span class="comment">//拿起左筷</span></span><br><span class="line">        <span class="built_in">semWait</span>(chopstick[(i+<span class="number">1</span>)%<span class="number">5</span>]);    <span class="comment">//拿起右筷</span></span><br><span class="line">        <span class="built_in">semSignal</span>(mutex);</span><br><span class="line">        <span class="comment">/*进餐*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(chopstick[i]);    <span class="comment">//放下左筷</span></span><br><span class="line">        <span class="built_in">semSignal</span>(shopstick[(i+<span class="number">1</span>)%<span class="number">5</span>]);    <span class="comment">//放下右筷</span></span><br><span class="line">        <span class="comment">/*思考*/</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">parbegin</span> (<span class="built_in">philosopher</span>(<span class="number">0</span>), <span class="built_in">philosopher</span>(<span class="number">1</span>), <span class="built_in">philosopher</span>(<span class="number">2</span>), <span class="built_in">philosopher</span>(<span class="number">3</span>), <span class="built_in">philosopher</span>(<span class="number">4</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>分析：</p>
<p>哲学家进程要想正常进行就需要同时拿起左右两根筷子，一旦请求资源无法满足，就会进入阻塞态。</p>
</blockquote>
<p>方法二：</p>
<p>分析：根据“鸽笼原理”，只要最多只有四位哲学家并发争夺筷子进餐，那么肯定会有一位哲学家可以同时拿到两根筷子。为此我们定义如下信号量：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">semaphore chopstick[<span class="number">5</span>] = &#123;<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>&#125;;    <span class="comment">//用于实现对5根筷子的互斥访问</span></span><br><span class="line">semaphore room = <span class="number">4</span>;    <span class="comment">//最多允许4为哲学家进餐</span></span><br></pre></td></tr></table></figure>

<p>实现：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*philosopher*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">philosopher</span><span class="params">(<span class="keyword">int</span> i)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="comment">/*思考*/</span>;</span><br><span class="line">        <span class="built_in">semWait</span>(room);</span><br><span class="line">        <span class="built_in">semWait</span>(chopstick[i]);    <span class="comment">//拿起左筷</span></span><br><span class="line">        <span class="built_in">semWait</span>(chopstick[(i+<span class="number">1</span>)%<span class="number">5</span>]);    <span class="comment">//拿起右筷</span></span><br><span class="line">        <span class="comment">/*进餐*/</span>;</span><br><span class="line">        <span class="built_in">semSignal</span>(chopstick[i]);    <span class="comment">//放下左筷</span></span><br><span class="line">        <span class="built_in">semSignal</span>(shopstick[(i+<span class="number">1</span>)%<span class="number">5</span>]);    <span class="comment">//放下右筷</span></span><br><span class="line">        <span class="built_in">semSignal</span>(room);</span><br><span class="line">        <span class="comment">/*思考*/</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">parbegin</span> (<span class="built_in">philosopher</span>(<span class="number">0</span>), <span class="built_in">philosopher</span>(<span class="number">1</span>), <span class="built_in">philosopher</span>(<span class="number">2</span>), <span class="built_in">philosopher</span>(<span class="number">3</span>), <span class="built_in">philosopher</span>(<span class="number">4</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>方法三：</p>
<p>要求奇数号哲学家先拿左边的筷子，然后再拿右边的筷子；而偶数号的哲学家相反，先拿右边的筷子，再拿左边的筷子。在这种策略下，如果相邻的两个奇偶号哲学家都想吃饭，那么只会有其中一个可以拿起第一只筷子，另一个会直接阻塞。这就避免了占有一支后再等待另一支的情况。</p>
<p>首先定义如下信号量：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">semaphore chopstick[<span class="number">5</span>] = &#123;<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>&#125;;    <span class="comment">//用于实现对5根筷子的互斥访问</span></span><br></pre></td></tr></table></figure>

<p>实现：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*philosopher*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">philosopher</span><span class="params">(<span class="keyword">int</span> i)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">        <span class="keyword">if</span>(i % <span class="number">2</span> == <span class="number">1</span>)&#123;    <span class="comment">//奇数号哲学家</span></span><br><span class="line">            <span class="comment">/*思考*/</span>;</span><br><span class="line">            <span class="built_in">semWait</span>(chopstick[i]);    <span class="comment">//拿起左筷</span></span><br><span class="line">            <span class="built_in">semWait</span>(chopstick[(i+<span class="number">1</span>)%<span class="number">5</span>]);    <span class="comment">//拿起右筷</span></span><br><span class="line">            <span class="comment">/*进餐*/</span>;</span><br><span class="line">            <span class="built_in">semSignal</span>(chopstick[i]);    <span class="comment">//放下左筷</span></span><br><span class="line">            <span class="built_in">semSignal</span>(shopstick[(i+<span class="number">1</span>)%<span class="number">5</span>]);    <span class="comment">//放下右筷</span></span><br><span class="line">            <span class="comment">/*思考*/</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(i % <span class="number">2</span> == <span class="number">0</span>)&#123;    <span class="comment">//偶数号哲学家</span></span><br><span class="line">            <span class="comment">/*思考*/</span>;</span><br><span class="line">            <span class="built_in">semWait</span>(chopstick[(i+<span class="number">1</span>)%<span class="number">5</span>]);    <span class="comment">//拿起右筷</span></span><br><span class="line">            <span class="built_in">semWait</span>(chopstick[i]);    <span class="comment">//拿起左筷</span></span><br><span class="line">            <span class="comment">/*进餐*/</span>;</span><br><span class="line">            <span class="built_in">semSignal</span>(shopstick[(i+<span class="number">1</span>)%<span class="number">5</span>]);    <span class="comment">//放下右筷</span></span><br><span class="line">            <span class="built_in">semSignal</span>(chopstick[i]);    <span class="comment">//放下左筷</span></span><br><span class="line">            <span class="comment">/*思考*/</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">parbegin</span> (<span class="built_in">philosopher</span>(<span class="number">0</span>), <span class="built_in">philosopher</span>(<span class="number">1</span>), <span class="built_in">philosopher</span>(<span class="number">2</span>), <span class="built_in">philosopher</span>(<span class="number">3</span>), <span class="built_in">philosopher</span>(<span class="number">4</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<hr>
<h1 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h1><p>本篇还没结束，持续更新中。</p>
<p><em>（欢迎评论区批评指正）</em></p>

    </div>

    
    
    
      
  <div class="popular-posts-header">相关文章</div>
  <ul class="popular-posts">
    <li class="popular-posts-item">
      <div class="popular-posts-title"><a href="\next\2021\03\28\操作系统\操作系统学习笔记\" rel="bookmark">操作系统学习笔记</a></div>
    </li>
    <li class="popular-posts-item">
      <div class="popular-posts-title"><a href="\next\2021\06\09\操作系统\操作系统学习笔记-文件管理\" rel="bookmark">操作系统学习笔记-文件管理</a></div>
    </li>
    <li class="popular-posts-item">
      <div class="popular-posts-title"><a href="\next\2021\06\02\操作系统\操作系统学习笔记-I-O管理和磁盘调度\" rel="bookmark">操作系统学习笔记-I/O管理和磁盘调度</a></div>
    </li>
    <li class="popular-posts-item">
      <div class="popular-posts-title"><a href="\next\2021\05\30\操作系统\操作系统学习笔记-单处理器调度\" rel="bookmark">操作系统学习笔记-单处理器调度</a></div>
    </li>
    <li class="popular-posts-item">
      <div class="popular-posts-title"><a href="\next\2021\05\24\操作系统\操作系统学习笔记-虚拟内存\" rel="bookmark">操作系统学习笔记-虚拟内存</a></div>
    </li>
  </ul>


    <footer class="post-footer">
          <div class="reward-container">
  <div></div>
  <button>
    赞赏
  </button>
  <div class="post-reward">
      <div>
        <img src="https://cdn.jsdelivr.net/gh/CNhuazhu/Image/wechat.png" alt="花猪 微信">
        <span>微信</span>
      </div>
      <div>
        <img src="https://cdn.jsdelivr.net/gh/CNhuazhu/Image/alipay.jpg" alt="花猪 支付宝">
        <span>支付宝</span>
      </div>

  </div>
</div>

          <div class="post-tags">
              <a href="/next/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" rel="tag"><i class="fa fa-tag"></i> 操作系统</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/next/2021/04/21/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E5%B9%B6%E5%8F%91%E6%80%A7%EF%BC%9A%E4%BA%92%E6%96%A5%E5%92%8C%E5%90%8C%E6%AD%A5/" rel="prev" title="操作系统学习笔记-并发性：互斥和同步">
                  <i class="fa fa-chevron-left"></i> 操作系统学习笔记-并发性：互斥和同步
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/next/2021/05/04/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-%E5%B9%B6%E5%8F%91%EF%BC%9A%E6%AD%BB%E9%94%81%E5%92%8C%E9%A5%A5%E9%A5%BF/" rel="next" title="操作系统学习笔记-并发：死锁和饥饿">
                  操作系统学习笔记-并发：死锁和饥饿 <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






    <div class="comments"><div id="twikoo-comments"></div></div>
</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 
  <span itemprop="copyrightYear">2021</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">花猪</span>
</div>
<div class="wordcount">
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-line"></i>
    </span>
      <span>站点总字数：</span>
    <span title="站点总字数">356k</span>
  </span>
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span>站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">5:23</span>
  </span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/mist/" rel="noopener" target="_blank">NexT.Mist</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <script src="https://cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@next-theme/pjax@0.5.0/pjax.min.js" integrity="sha256-3NkoLDrmHLTYj7csHIZSr0MHAFTXth7Ua/DDt4MRUAg=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js" integrity="sha256-yt2kYMy0w8AbtF89WXb2P1rfjcP/HTHLT7097U8Y5b8=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/medium-zoom@1.0.6/dist/medium-zoom.min.js" integrity="sha256-EdPgYcPk/IIrw7FYeuJQexva49pVRZNmt3LculEr7zM=" crossorigin="anonymous"></script>
<script src="/next/js/comments.js"></script><script src="/next/js/utils.js"></script><script src="/next/js/motion.js"></script><script src="/next/js/schemes/muse.js"></script><script src="/next/js/next-boot.js"></script><script src="/next/js/pjax.js"></script>

  
<script src="/next/js/third-party/search/local-search.js"></script>




  


  <script class="next-config" data-name="leancloud_visitors" type="application/json">{"enable":true,"app_id":"dh8GVAcIwU1TN4zhA5y63iW1-gzGzoHsz","app_key":"hzyAqDKjG4OBGrdPS7mKaOa7","server_url":null,"security":true}</script>
  <script src="/next/js/third-party/statistics/lean-analytics.js"></script>


  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdn.jsdelivr.net/npm/mathjax@3.2.0/es5/tex-mml-chtml.js","integrity":"sha256-r+3itOMtGGjap0x+10hu6jW/gZCzxHsoKrOd7gyRSGY="}}</script>
<script src="/next/js/third-party/math/mathjax.js"></script>


<script class="next-config" data-name="twikoo" type="application/json">{"enable":true,"visitor":true,"envId":"hexo-1g41404w9f800e94","el":"#twikoo-comments"}</script>
<script>
document.addEventListener('page:loaded', () => {
  NexT.utils.loadComments(CONFIG.twikoo.el)
    .then(() => NexT.utils.getScript(
      'https://cdn.jsdelivr.net/npm/twikoo/dist/twikoo.all.min.js',
      { condition: window.twikoo }
    ))
    .then(() => {
      twikoo.init(CONFIG.twikoo);
    });
});
</script>

</body>
</html>
